/*
  自定义控件
  有三种方式：
  1.组合其他 Widget
  2.通过 CustomPainter 绘制
    1)继承 CustomPainter 类，实现两个方法
      void paint(Canvas canvas, Size size)
      bool shouldRepaint(covariant CustomPainter oldDelegate)
    2)用 CustomPaint 包裹自定义的控件
    API名称	功能
    drawLine	画线
    drawPoint	画点
    drawPath	画路径
    drawImage	画图像
    drawRect	画矩形
    drawCircle	画圆
    drawOval	画椭圆
    drawArc	画圆弧
  3.实现 RenderObject
    
 */

import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(title: Text('自定义控件'),),
      body: HomePage(),
    ),
  ));
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: CustomPaint(
        size: Size(300, 300),
        painter: MyPainter(),
      ),
    );
  }
}

/*
  通过画布实现的五子棋
  可优化：
    将棋盘单独抽为一个组件，并设置其shouldRepaint回调值为false，然后将棋盘组件作为背景
    然后将棋子的绘制放到另一个组件中，这样每次落子时只需要绘制棋子
    以达到局部刷新
 */
class MyPainter extends CustomPainter {

  // Size 控件限定的宽高
  @override
  void paint(Canvas canvas, Size size) {
    print('MyPainter paint');
    double eWidth = size.width / 15;
    double eHeight = size.height / 15;

    //画棋盘背景
    var paint = Paint()
      ..isAntiAlias = true
      ..style = PaintingStyle.fill //填充
      ..color = Color(0x77cdb175); //背景为纸黄色
    canvas.drawRect(Offset.zero & size, paint);

    //画棋盘网格
    paint
      ..style = PaintingStyle.stroke //线
      ..color = Colors.black87
      ..strokeWidth = 1.0;

    for (int i = 0; i <= 15; ++i) {
      double dy = eHeight * i;
      canvas.drawLine(Offset(0, dy), Offset(size.width, dy), paint);
    }

    for (int i = 0; i <= 15; ++i) {
      double dx = eWidth * i;
      canvas.drawLine(Offset(dx, 0), Offset(dx, size.height), paint);
    }

    //画一个黑子
    paint
      ..style = PaintingStyle.fill
      ..color = Colors.black;
    canvas.drawCircle(
      Offset(size.width / 2 - eWidth / 2, size.height / 2 - eHeight / 2),
      min(eWidth / 2, eHeight / 2) - 2,
      paint,
    );

    //画一个白子
    paint.color = Colors.white;
    canvas.drawCircle(
      Offset(size.width / 2 + eWidth / 2, size.height / 2 - eHeight / 2),
      min(eWidth / 2, eHeight / 2) - 2,
      paint,
    );
  }

  // 在UI树重新build时，控件在绘制前都会先调用该方法以确定是否有必要重绘
  // 假如我们绘制的UI不依赖外部状态，那么就应该始终返回false，因为外部状态改变导致重新build时不会影响我们的UI外观
  // 如果绘制依赖外部状态，那么我们就应该在shouldRepaint中判断依赖的状态是否改变
  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }

}

